﻿#ifndef CUARTHOST_HPP
#define CUARTHOST_HPP

#include "common.h"
#include "uart.h"

using namespace std;
using namespace cv;

class CUartHost {
 private:
  char mRcvBuf[19];
  char mSendBuf[19];
  int mFd;

 public:
  CUartHost(/* args */);
  ~CUartHost();
  void Open();
  void Send(const vector<Point2f> &pts);
  void SendCalibrationStatus(bool status);
  void SendPoints(const vector<Point2f> &pts);
  bool Rcv(int &mode, int &width, int &height, int &target_height,
           int &target_side_length, int &part_num, int &udp_img_flag);
};

CUartHost::CUartHost() {
  mFd = -1;
  memset(mSendBuf, 0, sizeof(mSendBuf));
  memset(mRcvBuf, 0, sizeof(mRcvBuf));
}
CUartHost::~CUartHost() {}

void CUartHost::Open() {
  int err;
  int len;
  int err_count = 0;
  char PORT[] = "/dev/ttyAMA0";
  mFd = UART0_Open(mFd, PORT);  // 打开串口，返回文件描述符
  do {
    // err = UART0_Init(mFd,115200,0,8,1,'E');
    err = UART0_Init(mFd, 9600, 0, 8, 1, 'N');
    sleep(1);
    err_count++;
    if (err_count > 5) break;
  } while (FALSE == err || FALSE == mFd);
}

void CUartHost::Send(const vector<Point2f> &pts) {
  int step = 3, start = 0, end = 0;
  vector<Point2f> pts_new;
  for (const Point2f &pt : pts) {
    if (pt.x < 0 || pt.x > 1920 || pt.y < 0 || pt.y > 1080) continue;
    pts_new.push_back(pt);
  }
  int len = pts_new.size();
  while (len > start) {
    end = min(start + step, len);
    vector<Point2f> tmp(pts_new.begin() + start, pts_new.begin() + end);
    SendPoints(tmp);
    start += step;
  }
}
void CUartHost::SendCalibrationStatus(bool status) {
  memset(mSendBuf, 0, sizeof(mSendBuf));
  mSendBuf[0] = 0x55;
  mSendBuf[1] = 0xaa;
  for (int i = 2; i < 18; i++) {
    mSendBuf[i] = 0x00;
  }
  if (status) {
    mSendBuf[14] = 0x01;
  } else {
    mSendBuf[14] = 0x02;
  }
  mSendBuf[18] = 0xa0;
  UART0_Send(mFd, mSendBuf, sizeof(mSendBuf));
}

void CUartHost::SendPoints(const vector<Point2f> &pts) {
  memset(mSendBuf, 0, sizeof(mSendBuf));
  mSendBuf[0] = 0x55;
  mSendBuf[1] = 0xaa;
  char low, high;
  for (int i = 0; i < 3 && i < pts.size(); ++i) {
    // cout << "uart_send: i: " << i << " [" << pts[i].x << "," << pts[i].y <<
    // "]" <<endl;
    low = (char)((int)(pts[i].x) & 0xff);
    high = (char)(((int)(pts[i].x) & 0xff00) >> 8);
    mSendBuf[i * 4 + 2] = low;
    mSendBuf[i * 4 + 3] = high;
    low = (char)((int)(pts[i].y) & 0xff);
    high = (char)(((int)(pts[i].y) & 0xff00) >> 8);
    mSendBuf[i * 4 + 4] = low;
    mSendBuf[i * 4 + 5] = high;
  }
  mSendBuf[14] = 0x00;
  mSendBuf[15] = 0x00;
  mSendBuf[16] = 0x00;
  mSendBuf[17] = 0x00;
  mSendBuf[18] = 0xa0;
  UART0_Send(mFd, mSendBuf, sizeof(mSendBuf));
  // memset(mSendBuf, 0, sizeof(mSendBuf));
}

bool CUartHost::Rcv(int &mode, int &width, int &height, int &target_height,
                    int &target_side_length, int &part_num, int &udp_img_flag) {
  bool flag_updated = false;
  uchar mode_tmp = 0;
  uchar part_num_tmp = 0;
  uchar udp_img_flag_tmp = 0;
  int len = UART0_Recv(mFd, mRcvBuf, sizeof(mRcvBuf));
  uchar low_x_pixel, high_x_pixel, low_y_pixel, high_y_pixel;
  uchar low_target_height, high_target_height, low_target_side_length,
      high_target_side_length;
  if (len == sizeof(mRcvBuf)) {
    if (mRcvBuf[0] == 0x55 && mRcvBuf[1] == 0xaa && mRcvBuf[18] == 0xff) {
      memcpy(&low_x_pixel, mRcvBuf + 2, 1);
      memcpy(&high_x_pixel, mRcvBuf + 3, 1);
      memcpy(&low_y_pixel, mRcvBuf + 4, 1);
      memcpy(&high_y_pixel, mRcvBuf + 5, 1);
      memcpy(&low_target_height, mRcvBuf + 6, 1);
      memcpy(&high_target_height, mRcvBuf + 7, 1);
      memcpy(&low_target_side_length, mRcvBuf + 8, 1);
      memcpy(&high_target_side_length, mRcvBuf + 9, 1);

      memcpy(&mode_tmp, mRcvBuf + 10, 1);
      memcpy(&part_num_tmp, mRcvBuf + 11, 1);
      memcpy(&udp_img_flag_tmp, mRcvBuf + 12, 1);
      mode = mode_tmp;
      part_num = part_num_tmp;
      udp_img_flag = udp_img_flag_tmp;
      width = (int)high_x_pixel * 256 + low_x_pixel;
      height = (int)high_y_pixel * 256 + low_y_pixel;
      target_height = (int)high_target_height * 256 + low_target_height;
      target_side_length =
          (int)high_target_side_length * 256 + low_target_side_length;
      cout << "mode: " << mode << " width: " << width << " height: " << height
           << " part_num: " << part_num << " udp_img_flag: " << udp_img_flag
           << " target_height: " << target_height
           << " tatget_side_length: " << target_side_length << endl;
      flag_updated = true;
    }
  }
  return flag_updated;
}

#endif
